namespace Warehouse

open System
open System.Collections.ObjectModel
open FSharp.Windows

[<AbstractClass>]
[<AllowNullLiteral>]
type InvoiceLineItemModel() = 
    inherit EntityModel<DataModel.InvoiceLineItem>()

    abstract UPC : DataModel.UPC with get, set
    abstract Quantity : int with get, set
    abstract BasePrice : decimal with get, set
    abstract Commission : decimal with get, set
    abstract IsDefaultCommission : bool with get, set

    [<NotifyDependencyChanged>]
    member this.UPCode = this.UPC.Code

    [<NotifyDependencyChanged>]
    member this.Size = 
        let product = this.UPC.Product
        sprintf "%s %s" product.SizeOrColor product.Unit.Name

    [<NotifyDependencyChanged>]
    member this.ExtendedPrice = this.BasePrice * (1M + this.Commission/100M) |> Decimal.round2

    [<NotifyDependencyChanged>]
    member this.Total = decimal this.Quantity * this.ExtendedPrice |> Decimal.round2

    override this.Init() = 
        this.UPC <- this.Entity.UPC
        this.Quantity <- this.Entity.Quantity
        this.BasePrice <- this.Entity.BasePrice
        this.Commission <- this.Entity.Commission
        this.IsDefaultCommission <- this.Entity.IsDefaultCommission

    override this.Flush() =
        this.Entity.UPC <- this.UPC
        this.Entity.Quantity <- this.Quantity
        this.Entity.BasePrice <- this.BasePrice
        this.Entity.Commission <- this.Commission
        this.Entity.IsDefaultCommission <- this.IsDefaultCommission

    override this.Compute() = 
        this.IsDefaultCommission <- this.UPC.Product.DefaultBrandCommissionForClient() = this.Commission

[<AbstractClass>]
[<AllowNullLiteral>]
type InvoiceDetailsModel() = 
    inherit EntityModel<DataModel.Invoice>()

    abstract Id : int with get, set
    abstract Client : DataModel.Client with get, set
    abstract Date : DateTime with get, set
    abstract Note : string with get, set
    abstract CommissionOverride : decimal Nullable with get, set

    [<NotifyDependencyChanged>]
    member this.Total = 
        if this.LineItems = null then 0M else this.LineItems |> Seq.sumBy(fun li -> li.Total)
    [<NotifyDependencyChanged>]
    member this.TotalQuantity =  
        if this.LineItems = null then 0 else this.LineItems |> Seq.sumBy(fun li -> li.Quantity)

    abstract AllClientsList : DataModel.Client seq with get, set
    [<NotifyCollectionChanged>]
    abstract LineItems : InvoiceLineItemModel ObservableCollection with get, set
    abstract SelectedLineItem : InvoiceLineItemModel with get, set

    abstract IsOperationInProgress : bool with get, set

    override this.Init() = 
        this.Id <- this.Entity.Id
        this.Client <- this.Entity.Client
        this.Date <- this.Entity.Date
        this.Note <- this.Entity.Note
        this.LineItems <- this.Entity.InvoiceLineItems |> Seq.map EntityModel.Load |> ObservableCollection.ofSeq
        this.Compute()

    override this.Flush()=
        this.Entity.Client <- this.Client
        this.Entity.Date <- this.Date
        this.Entity.Note <- this.Note
        for li in this.LineItems do
            li.UpdateEntity()
            li.Entity.Invoice <- this.Entity

    override this.HasErrors = 
        base.HasErrors || (this.LineItems |> Seq.exists (fun li -> li.HasErrors))

    member this.Validate(repository : DataModel.Repository) = 
        this |> Validation.objectRequired <@ fun m -> m.Client @>
        for li in this.LineItems do
            if li.UPC.Id = 0
            then
                li |> Validation.setError <@ fun m -> m.UPCode @> "UPC doesn't exist in database."
            else
                li |> Validation.objectRequired <@ fun m -> m.UPC @> 
                li |> Validation.positive <@ fun m -> m.Quantity @>
                let inStock = repository.AvailableQuantityByUPC li.UPC
                let quantity = if li.IsNewEntity then li.Quantity else li.Quantity - li.Entity.Quantity 
                if this.Client.IsNotLushEssence() && quantity > 0 && quantity > inStock
                then
                    let message = sprintf "Oversell attempt. %i additional items requested. %i items available at warehouse." quantity inStock
                    li |> Validation.setError <@ fun m -> m.Quantity @> message

    member this.Save repository = 
        this.Compute()
        for li in this.LineItems do li.Compute()
        this.SaveEntity repository
        if this.Id = 0 
        then
            this.Id <- this.Entity.Id

        
        


        
